//
// Created by bill3000 on 2/9/21.
//

#ifndef INTELLI_FRUIT_HPP
#define INTELLI_FRUIT_HPP

#include <map>
#include "../mq/queue.hpp"

#include "macros.hpp"
#include "state.hpp"
#include "event.hpp"
#include "action.hpp"
#include "transition.hpp"

#include <opencv2/opencv.hpp>

class FruitFSM {
public:
    static void start_sorting_kernel_thread();
    static void wait_sorting_kernel_thread();
    static void stop_sorting_kernel_thread();
    static void dispose();
    ~FruitFSM();

private:
    static void* sorting_kernel_thread(void *data);

    FruitFSM();
    void make_fsm();
    void make_actions();
    void running_analysis();

    void add_state(State& state);
    void add_transition(Transition& transition);

    int set_current(unsigned int state_code);
    State* get_state(unsigned int state_code);
    void process(Event* event);
    int run(unsigned int action_code, Event *event);

    std::map<unsigned int, State> machine;
    std::map<unsigned int, Action> actions;
    State *current;

    static FruitFSM *fruit;
    static Queue *mq;
    static pthread_t sorting_kernel_thread_id;
    static Statistics statistics;

    static bool learning;
    static cv::VideoCapture *cam1, *cam2, *cam3, *cam4;
    static SizeModel learned_size_model[3];  //learned_size_model: learned size model
    static SizeModel loaded_size_model[3];  //loaded_size_model: loaded size model
    static bool size_model_loaded, sugar_model_loaded;
    static bool sorting;
    static pthread_t addon_sugar_thread_id;
    static std::map<long, float> sugar_ann_nirid_to_sugar;
    static pthread_t sugar_learning_thread_id;
    static int sugar_learning_progress_in_percent;

    static int action_none(Event *) {return 0;};

    static int action_open_cam(Event *event);
    static int action_start_conveyor(Event *event);
    static int action_stop_conveyor(Event *event);

    static int action_get_cam_param(Event *event);
    static int action_preview_still_image(Event *event);
    static int action_preview_moving_image(Event *event);
    static int action_modify_cam_param(Event *event);

    static int action_start_size_auto_learning(Event *event);
    static int action_get_size_auto_progress_image(Event *event);
    static int action_stop_size_auto_learning(Event *event);
    static int action_learning_sal_return_learned_result_to_ui(Event* event);
    static int action_view_size_learning_sample(Event *event);
    static int action_save_size_learning_model(Event *event);
    static int action_start_semi_size_learning(Event *event);
    static int action_stop_semi_size_learning(Event *event);
    static int action_learning_ssl_return_learned_result_to_ui(Event* event);

    static int action_start_sugar_annotation(Event *event);
    static int action_get_next_nir_image_and_set_previous_nir_sugar(Event *event);
    static int action_stop_sugar_annotation(Event *event);
    static int action_save_sugar_annotation(Event *event);
    static int action_start_sugar_learning(Event *event);
    static int action_query_sugar_learning_progress(Event *event);
    static int action_save_sugar_learned_model(Event *event);
    static int action_cancel_sugar_learning(Event *event);

    static int action_load_size_model(Event *event);
    static int action_load_sugar_model(Event *event);
    static int action_start_sorting(Event *event);
    static int action_view_sorting_process_image(Event *event);
    static int action_view_sorting_statistics(Event *event);
    static int action_pause_sorting(Event *event);

    static int action_get_history_sorting_data(Event *event);
    static int action_view_history_statistics(Event *event);
    static int action_delete_history_data(Event *event);

    static int action_put_event_back_to_queue(Event *event);

    static cv::VideoCapture* util_get_cam_by_id(int id);
    static std::string util_get_now_time_milli_string();
    static void util_delete_dir_content(const char* path);
    static void util_get_dir_content(const std::string& path, std::vector<std::string> &fns);
    static int util_copy_file(const std::string& sdir, const std::string& fn, const std::string& ddir);
    static void util_get_current_second_time_in_string(std::string &ss);
    static int util_create_multi_dirs(const std::string& path);
    static int util_get_min_from_multi_int(int num,...);
    static int util_get_max_from_multi_int(int num,...);

    static int learning_start_size_auto_learning_thread(int catalog_num);
    static void* learning_size_auto_learning_thread(void *data);
    static int learning_start_size_semi_learning_thread(int size);
    static void * learning_size_semi_learning_thread(void *data);
    static void learning_sal_get_perfect_image_from_series(std::map<std::string, int> &cam1_name_area_map, std::map<std::string, int> &cam2_name_area_map, std::map<std::string, int> &cam3_name_area_map);
    static void learning_ssl_copy_file_to_dest_and_compute_means(int size, std::map<std::string, int> &cam1_name_area_map, std::map<std::string, int> &cam2_name_area_map, std::map<std::string, int> &cam3_name_area_map);

    static int learning_start_sugar_ann_thread(int catalog_num);
    static void* learning_sugar_ann_thread(void *data);
    static void learning_sugar_ann_get_perfect_image_from_series();
    static int learning_start_sugar_learning_thread();
    static void* learning_sugar_learning_thread(void *data);

    static int start_sorting_thread(int size_and_sugar);
    static void* sorting_thread(void *data);
    static void sorting_by_size(int andbysugar = 0);
    static void sorting_by_sugar();
    static void sorting_by_size_and_sugar();
    static int start_the_addon_sugar_thread();
    static void* addon_sugar_thread(void *data);

    static int algorithm_get_image_area(const cv::Mat &m);
    static SizeModel algorithm_sal_kmeans_learning(std::map<std::string, int> &cam_name_area_map, int k, const std::string& size);
    static int algorithm_analysis_size_and_defect();
    static int algorithm_analysis_sugar();

};

#endif //INTELLI_FRUIT_HPP
